﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace PSE.Deployment.Util
{
    public static class CloneHelper
    {
        /// <summary>
        /// Cria uma cópia completa de um objeto
        /// </summary>
        /// <param name="obj">Objeto a ser clonado</param>
        /// <returns>Instância do objeto clonado</returns>
        public static object Clone(object obj)
        {
            if (obj == null)
                throw new ArgumentNullException("obj");

            object clonedObj = null;
            byte[] binObj = null;

            lock (obj)
            {
                // Serializando
                binObj = Serialize(obj);

                // Deserializando
                clonedObj = Deserialize(binObj);
            }

            return clonedObj;
        }

        /// <summary>
        /// Serializa um objeto de forma binária
        /// </summary>
        /// <param name="obj">Instância do objeto a ser serializado</param>
        /// <returns>Array de bytes contendo o objeto serializado</returns>
        public static byte[] Serialize(object obj)
        {
            if (obj == null)
                throw new ArgumentNullException("obj");

            byte[] arrByte = null;
            MemoryStream stream = null;
            BinaryFormatter formater = null;

            try
            {
                stream = new MemoryStream();
                formater = new BinaryFormatter();

                //Serializando
                formater.Serialize(stream, obj);

                stream.Position = 0;

                //Convertendo Stream em Array de Bytes
                arrByte = new byte[stream.Length];
                stream.Read(arrByte, 0, Convert.ToInt32(stream.Length));
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }

            return arrByte;
        }

        /// <summary>
        /// Deserializa um objeto de forma binária
        /// </summary>
        /// <param name="obj">Array de bytes contendo o objeto serializado</param>
        /// <returns>Instância do objeto</returns>
        public static object Deserialize(byte[] obj)
        {
            if (obj == null)
                throw new ArgumentNullException("obj");

            MemoryStream reader = null;
            BinaryFormatter formatter = null;
            object objFromBF = null;

            try
            {
                reader = new MemoryStream(obj);
                formatter = new BinaryFormatter();

                reader.Position = 0;
                
                //Deserializando
                objFromBF = formatter.Deserialize(reader);
            }
            finally
            {
                if (reader != null)
                    reader.Close();
            }

            return objFromBF;
        }
    }
}
